#pragma once
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Polyhedron_items_with_id_3.h>
#include <CGAL/Nef_polyhedron_3.h>
#include <CGAL/IO/Nef_polyhedron_iostream_3.h>
#include <CGAL/OFF_to_nef_3.h>
#include <CGAL/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h>
//typedef CGAL::Simple_cartesian<double> KBase;
typedef CGAL::Exact_predicates_inexact_constructions_kernel KBase;
//typedef CGAL::Exact_predicates_exact_constructions_kernel KBase;
template<typename Point>
class PolyLinePntBase
{
public:
	PolyLinePntBase()
	{

	}
	PolyLinePntBase(Point pnt, bool isConnectNext = true)
	{
		m_Pnt = pnt;
		m_isConnectNext = isConnectNext;
	}
	inline void SetPnt(const Point& pnt)  { m_Pnt = pnt; };
	inline void SetConnectNext(bool isConnectNext)  {  m_isConnectNext = isConnectNext; };
	inline Point GetPnt() const { return m_Pnt; };
	inline Point& GetPnt()  { return m_Pnt; };
	inline bool IsConnectNext() const { return m_isConnectNext; };
protected:
	Point m_Pnt;
	bool m_isConnectNext;
};
typedef PolyLinePntBase<KBase::Point_3> PolyPnt;
//typedef pair<KBase::Point_3, bool> PolyPnt;
typedef CGAL::Bbox_3 Box3;
typedef KBase::Point_3 Point_3;
typedef KBase::Point_2 Point_2;
typedef KBase::Segment_3 Segment_3;
typedef KBase::Vector_3 Vector_3;
typedef KBase::Vector_2 Vector_2;
typedef CGAL::Surface_mesh<KBase::Point_3> Surface_mesh;
typedef Surface_mesh::Vertex_index mesh_vertex_descriptor;
typedef Surface_mesh::Face_index mesh_face_descriptor;

extern void InitLoadDataAsOff(CFileLoadData& fp);
extern void InitSaveDataAsOff(CFileSaveData& fp);
extern void SaveMeshAsOff(const Surface_mesh& mesh, CFileSaveData& fp);
extern void SaveMeshAsOff(const Surface_mesh& mesh, string sFileName);
extern void LoadMeshAsOff(Surface_mesh& mesh, string sFileName);
extern void LoadMeshAsOff(Surface_mesh& mesh, CFileLoadData& fp);
inline void VeNormal(Vector_3& ve)
{
	ve /= sqrt(CGAL::to_double(ve.squared_length()));
};
inline Vector_3 VeNormalTo(const Vector_3& ve)
{
	Vector_3 ret = ve;
	VeNormal(ret);
	return ret;
};
inline  double VeLength(const Vector_3& ve)
{
	return sqrt(CGAL::to_double(ve.squared_length()));
};
inline  double VeLength2(const Vector_3& ve)
{
	Vector_2 ve1 = Vector_2(ve[0], ve[1]);
	return sqrt(CGAL::to_double(ve.squared_length()));
};
template<typename T>
string PrintLine(T from, T to, int iPntSize = 3)
{
	string ret;
	ret += "line ";
	for (auto pnt = from; pnt != to; ++pnt)
	{
		auto pnt0 = *pnt;
		for (int i = 0; i < iPntSize; ++i)
		{
			ret = ret + to_string(CGAL::to_double(pnt0[i]));
			if (i != iPntSize - 1)
			{
				ret += ",";
			}
		}
		ret = ret + "\n";
	}
	return ret;
}

extern string PrintVLine(const vector<vector<Point_3>>& vLine);

template<typename T>
string PrintSeg(T from, T to)
{
	string ret;
	for (auto seg2 = from; seg2 != to; ++seg2)
	{
		ret += "line ";
		auto pnt0 = seg2->source();
		ret = ret + to_string(CGAL::to_double(pnt0[0])) + "," + to_string(CGAL::to_double(pnt0[1])) + "," + to_string(CGAL::to_double(pnt0[2])) + "\n";
		auto pnt1 = seg2->target();
		ret = ret + to_string(CGAL::to_double(pnt1[0])) + "," + to_string(CGAL::to_double(pnt1[1])) + "," + to_string(CGAL::to_double(pnt1[2])) + "\n";

		ret += "\n";
	}
	return ret;
}